home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- *
- * ATTENTION!!!
- *
- * THIS FILE HAS BEEN MODIFIED!!! IT IS NOT PART OF THE OFFICAL
- * POV-RAY 2.2 DISTRIBUTION!!!
- *
- * THIS FILE IS PART OF "FASTER THAN POV-RAY" (VERSION 2.2),
- * A SPED-UP VERSION OF POV-RAY 2.2. USE AT YOUR OWN RISK!!!!!!
- *
- * New files: addon0.c, addon1.c, addon2.c, addon3.c, addon.h
- *
- * The additional modules were written by Dieter Bayer.
- *
- * Send comments, suggestions, bugs, ideas ... to:
- *
- * e-mail: dieter@cip.e-technik.uni-erlangen.de
- * CIS: 100255.3074
- *
- * All changed/added lines are enclosed in #ifdef DB_CODE ... #endif
- *
- * The vista projection was taken from:
- *
- * A. Hashimoto, T. Akimoto, K. Mase, and Y. Suenaga,
- * "Vista Ray-Tracing: High Speed Ray Tracing Using Perspective
- * Projection Image", New Advances in Computer Graphics, Proceedings
- * of CG International '89, R. A. Earnshaw, B. Wyvill (Eds.),
- * Springer, ..., pp. 549-560
- *
- * The idea for the light buffer was taken from:
- *
- * E. Haines and D. Greenberg, "The Light Buffer: A Shadow-Testing
- * Accelerator", IEEE CG&A, Vol. 6, No. 9, Sept. 1986, pp. 6-16
- *
- *****************************************************************************/
-
- /****************************************************************************
- * addon1.c
- *
- * This module was written by Dieter Bayer.
- *
- * This module contains functions used only for the vista buffer.
- *
- * 01.03.1994 : Creation
- *
- * 29.04.1994 : Version 2.0
- *
- ******************************************************************************/
-
- #include <time.h>
- #include "frame.h"
- #include "vector.h"
- #include "povproto.h"
- #include "addon.h"
-
- #ifdef DB_CODE
-
- /* count project tests */
- #define COUNT_PROJECT_TESTS
-
- #define NUMBER_OF_TYPES 18
- #define TYPE_BICUBIC_PATCH 0
- #define TYPE_BLOB 1
- #define TYPE_BOX 2
- #define TYPE_CONE 3
- #define TYPE_CSG_INTERSECTION 4
- #define TYPE_CSG_MERGE 5
- #define TYPE_CSG_UNION 6
- #define TYPE_DISC 7
- #define TYPE_ELLIPSOID 8
- #define TYPE_HEIGHT_FIELD 9
- #define TYPE_LIGHT_SOURCE 10
- #define TYPE_PLANE 11
- #define TYPE_POLY 12
- #define TYPE_QUADRIC 13
- #define TYPE_SMOOTH_TRIANGLE 14
- #define TYPE_SPHERE 15
- #define TYPE_TRIANGLE 16
- #define TYPE_UNKNOWN 17
-
- #define NUMBER_OF_FLAGS 9
- #define FLAG_SUM 0
- #define FLAG_INFINITE 1
- #define FLAG_SCREEN_FILLING 2
- #define FLAG_USED_IN_CSG 3
- #define FLAG_INVISIBLE 4
- #define FLAG_BOUNDED 5
- #define FLAG_CLIPPED 6
- #define FLAG_BOUND_OBJECT 7
- #define FLAG_CLIP_OBJECT 8
-
-
-
- /*****************************************************************************
- * external variables
- ******************************************************************************/
-
- extern long Number_Of_Rays;
- extern FRAME Frame;
- extern int Trace_Level;
- extern int Use_Slabs;
- extern DBL Max_Trace_Level;
- extern time_t tstart, tstop;
- extern unsigned int Options;
- extern OBJECT *Root_Object;
-
- extern METHODS Bicubic_Patch_Methods;
- extern METHODS Blob_Methods;
- extern METHODS Box_Methods;
- extern METHODS Cone_Methods;
- extern METHODS Csg_Height_Field_Methods;
- extern METHODS CSG_Intersection_Methods;
- extern METHODS CSG_Merge_Methods;
- extern METHODS CSG_Union_Methods;
- extern METHODS Disc_Methods;
- extern METHODS Ellipsoid_Methods;
- extern METHODS Height_Field_Methods;
- extern METHODS Light_Source_Methods;
- extern METHODS Plane_Methods;
- extern METHODS Poly_Methods;
- extern METHODS Quadric_Methods;
- extern METHODS Smooth_Triangle_Methods;
- extern METHODS Sphere_Methods;
- extern METHODS Triangle_Methods;
-
- extern unsigned MAXQUEUE;
- extern unsigned long totalQueues, totalQueueResets, nChecked, nEnqueued;
-
- extern size_t Mem_Vista_Buffer;
-
-
-
- /*****************************************************************************
- * Non-static variables
- ******************************************************************************/
-
- PROJECT_TREE_NODE *Root_Vista;
- unsigned long Project_Tests = 0, Project_Tests_Succeeded = 0;
- unsigned Project_Algorithm = PROJECTIONS_WITH_LEAF_SLABS;
-
-
-
-
- /*****************************************************************************
- * Static variables
- ******************************************************************************/
-
- static DBL distance;
- static MATRIX WC2VC, WC2VCinv;
- static VECTOR O, U, V, W;
-
- /* Planes for 3d-clipping */
-
- static VECTOR VIEW_VX1 = {-0.8944271910, 0.0, -0.4472135955};
- static VECTOR VIEW_VX2 = { 0.8944271910, 0.0, -0.4472135955};
- static VECTOR VIEW_VY1 = {0.0, -0.8944271910, -0.4472135955};
- static VECTOR VIEW_VY2 = {0.0, 0.8944271910, -0.4472135955};
- static DBL VIEW_DX1 = 0.4472135955;
- static DBL VIEW_DX2 = 0.4472135955;
- static DBL VIEW_DY1 = 0.4472135955;
- static DBL VIEW_DY2 = 0.4472135955;
-
- /* Queues */
-
- static Qelem *Tree_Leaf_Queue;
- static PROJECT_TREE_NODE **Tree_Node_Queue;
-
-
-
- /*****************************************************************************
- * Static functions
- ******************************************************************************/
-
- static void Project_rectangle PARAMS((PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, VECTOR P4, int *visible));
- static void Project_triangle PARAMS((PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, int *visible));
-
- static void Project_Bbox PARAMS((PROJECT *Project, VECTOR *Points, int *visible));
- static void Project_Bounds PARAMS((PROJECT *Project, BBOX *Bounds, int *visible));
-
- static void Get_Perspective_Projection PARAMS((OBJECT *Object, PROJECT *Project, int infinite));
-
- static void Project_Object PARAMS((OBJECT *Object, PROJECT *Project));
-
- static void Project_Bicubic_Patch PARAMS((PROJECT *Project, OBJECT *Object));
- static void Project_Box PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
- static void Project_Height_Field PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
- static void Project_Sphere PARAMS((PROJECT *Project, OBJECT *Object));
- static void Project_Triangle PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
- static void Project_Smooth_Triangle PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
-
- static void Get_Ellipse_Projection PARAMS((PROJECT *Project, DBL a20, DBL a02, DBL a11, DBL a10, DBL a01, DBL a00));
-
- static void Transform_Point PARAMS((VECTOR *P));
-
- static void Project_Bounding_Slab PARAMS((PROJECT *Project, PROJECT_TREE_NODE **Tree, OBJECT *Object));
-
- static void Create_Rayinfo PARAMS((RAY *Ray, RAYINFO *rayinfo));
-
- static int Intersect_Vista_Tree PARAMS((RAY *Ray, PROJECT_TREE_NODE *Tree, int x, INTERSECTION *Best_Intersection));
-
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Init_Project_Tree_Queues
- *
- * ARGUMENTS : none
- *
- * MODIFIED ARGS : none
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Init queues for descending project tress, i.e. allocate memory needed.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Init_Project_Tree_Queues()
- {
- Tree_Leaf_Queue = (Qelem *)VB_malloc(MAXQUEUE*sizeof(Qelem));
-
- if (Tree_Leaf_Queue == NULL)
- {
- Fatal_MAError("priority queue for vista/light buffer");
- }
-
- Tree_Node_Queue = (PROJECT_TREE_NODE **)VB_malloc(MAXQUEUE*sizeof(PROJECT_TREE_NODE *));
-
- if (Tree_Node_Queue == NULL)
- {
- Fatal_MAError("priority queue for vista/light buffer");
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Prune_Vista_Tree
- *
- * ARGUMENTS : y - Current scanline number
- *
- * MODIFIED ARGS : none
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Prune vista tree, i.e. mark all nodes not on the current line inactive.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Prune_Vista_Tree(y)
- int y;
- {
- unsigned size;
- unsigned short i;
- PROJECT_TREE_NODE *Node, *Sib;
-
- size = 0;
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((y < Root_Vista->Project.y1) || (y > Root_Vista->Project.y2))
- {
- /* Root doesn't lie on current line --> prune root */
-
- Root_Vista->is_leaf |= PRUNE_TEMPORARY;
- }
- else
- {
- /* Root lies on current line --> unprune root */
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- Root_Vista->is_leaf &= PRUNE_TEMPORARY_INVERS;
-
- Tree_Node_Queue[size++] = Root_Vista;
- }
-
- while (size > 0)
- {
- Node = Tree_Node_Queue[--size];
-
- if (Node->is_leaf & TRUE)
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((y < Node->Project.y1) || (y > Node->Project.y2))
- {
- /* Leaf doesn't lie on current line --> prune leaf */
-
- Node->is_leaf |= PRUNE_TEMPORARY;
- }
- else
- {
- /* Leaf lies on current line --> unprune leaf */
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- Node->is_leaf &= PRUNE_TEMPORARY_INVERS;
- }
- }
- else
- {
- /* Check siblings of the node */
-
- for (i = 0; i < Node->Entries; i++)
- {
- Sib = Node->Entry[i];
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((y < Sib->Project.y1) || (y > Sib->Project.y2))
- {
- /* Sibling doesn't lie on current line --> prune sibling */
-
- Sib->is_leaf |= PRUNE_TEMPORARY;
- }
- else
- {
- /* Sibling lies on current line --> unprune sibling */
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- Sib->is_leaf &= PRUNE_TEMPORARY_INVERS;
-
- /* Add sibling to list */
-
- Tree_Node_Queue[size++] = Sib;
- }
- }
- }
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Trace_Primary_Ray
- *
- * ARGUMENTS : Ray - Current ray
- * Colour - Ray's colour
- * x - Current x-coordinate
- *
- * MODIFIED ARGS : colour
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Trace a primary ray using the vista tree.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Trace_Primary_Ray (Ray, Colour, x)
- RAY *Ray;
- COLOUR *Colour;
- int x;
- {
- INTERSECTION Best_Intersection;
-
- COOPERATE
-
- Number_Of_Rays++;
-
- if (Trace_Level > (int)Max_Trace_Level)
- return;
-
- Colour->Red = Colour->Green = Colour->Blue = 0.0;
-
- Best_Intersection.Depth = BOUND_HUGE;
-
- /* What objects does this ray intersect? */
-
- if (Intersect_Vista_Tree(Ray, Root_Vista, x, &Best_Intersection))
- {
- Determine_Apparent_Colour (&Best_Intersection, Colour, Ray);
- }
- else
- {
- if (Frame.Fog_Distance > 0.0)
- {
- *Colour = Frame.Fog_Colour;
- }
- else
- {
- *Colour = Frame.Background_Colour;
- }
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Create_Rayinfo
- *
- * ARGUMENTS : Ray - Current ray
- * rayinfo - Rayinfo structure
- *
- * MODIFIED ARGS : rayinfo
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Calculate the rayinfo structure for a given ray. It's need for
- * intersection the ray with bounding boxes.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Create_Rayinfo(Ray, rayinfo)
- RAY *Ray;
- RAYINFO *rayinfo;
- {
- DBL t;
-
- /* Create the direction vectors for this ray */
-
- rayinfo->slab_num = Ray->Initial;
-
- if ((rayinfo->nonzero.x = ((t = Ray->Direction.x) != 0.0)) != 0)
- {
- rayinfo->slab_den.x = 1.0 / t;
- rayinfo->positive.x = (Ray->Direction.x > 0.0);
- }
-
- if ((rayinfo->nonzero.y = ((t = Ray->Direction.y) != 0.0)) != 0)
- {
- rayinfo->slab_den.y = 1.0 / t;
- rayinfo->positive.y = (Ray->Direction.y > 0.0);
- }
-
- if ((rayinfo->nonzero.z = ((t = Ray->Direction.z) != 0.0)) != 0)
- {
- rayinfo->slab_den.z = 1.0 / t;
- rayinfo->positive.z = (Ray->Direction.z > 0.0);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Intersect_Vista_Tree
- *
- * ARGUMENTS : Ray - Primary ray
- * Tree - Vista tree's top-node
- * x - Current x-coordinate
- * Best_Intersection - Intersection found
- *
- * MODIFIED ARGS : Best_Intersection
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Intersect a PRIMARY ray with the vista tree
- * (tree pruning is used can be primary ray!!!).
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static int Intersect_Vista_Tree(Ray, Tree, x, Best_Intersection)
- RAY *Ray;
- PROJECT_TREE_NODE *Tree;
- int x;
- INTERSECTION *Best_Intersection;
- {
- INTERSECTION New_Intersection;
- unsigned short i;
- unsigned Qsize, size;
- int Found;
- RAYINFO rayinfo;
- DBL key;
- OBJECT *Object;
- PROJECT_TREE_NODE *Node;
-
- /* Start with an empty priority queue */
-
- Qsize = 0;
-
- Found = FALSE;
-
- totalQueueResets++;
-
- /* Which algorithm to use? */
-
- switch (Project_Algorithm)
- {
- /************************************************************************
- * Do not use any bounding slab tests. just use their projections.
- *************************************************************************/
-
- case PROJECTIONS_WITHOUT_SLABS :
-
- /* Check root */
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- Tree_Node_Queue[Qsize++] = Tree;
- }
-
- while (Qsize > 0)
- {
- Tree = Tree_Node_Queue[--Qsize];
-
- switch (Tree->is_leaf)
- {
- case FALSE:
-
- /* Check siblings of the unpruned node in 2d */
-
- for (i = 0; i < Tree->Entries; i++)
- {
- Node = Tree->Entry[i];
-
- /* Check unpruned siblings only */
-
- if (Node->is_leaf < PRUNE_CHECK)
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Node->Project.x1) && (x <= Node->Project.x2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- /* Add node to node queue */
-
- if (Qsize >= MAXQUEUE)
- Fatal_Error("Node queue overflow.\n");
-
- Tree_Node_Queue[Qsize++] = Node;
- }
- }
- }
-
- break;
-
- case TRUE:
-
- /* Unpruned leaf --> test object */
-
- if (Intersection(&New_Intersection, ((PROJECT_TREE_LEAF *)Tree)->Object, Ray))
- {
- if (New_Intersection.Depth < Best_Intersection->Depth)
- {
- *Best_Intersection = New_Intersection;
- Found = TRUE;
- }
- }
-
- break;
-
- /* default:
-
- The node/leaf is pruned and needn't be checked */
-
- }
- }
-
- break;
-
-
-
- /************************************************************************
- * Use bounding slab tests for leaves (i.e. objects) in the tree.
- *************************************************************************/
-
- case PROJECTIONS_WITH_LEAF_SLABS :
-
- /* Create the direction vectors for this ray */
-
- Create_Rayinfo(Ray, &rayinfo);
-
- /* Fill the priority queue with all possible candidates */
-
- size = 0;
-
- /* Check root */
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- Tree_Node_Queue[size++] = Tree;
- }
-
- while (size > 0)
- {
- Tree = Tree_Node_Queue[--size];
-
- switch (Tree->is_leaf)
- {
- case FALSE:
-
- /* Check siblings of the unpruned node in 2d */
-
- for (i = 0; i < Tree->Entries; i++)
- {
- Node = Tree->Entry[i];
-
- /* Check unpruned siblings only */
-
- if (Node->is_leaf < PRUNE_CHECK)
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Node->Project.x1) && (x <= Node->Project.x2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- /* add node to node queue */
-
- if (size >= MAXQUEUE)
- Fatal_Error("Node queue overflow.\n");
-
- Tree_Node_Queue[size++] = Node;
- }
- }
- }
-
- break;
-
- case TRUE:
-
- /* Unpruned leaf --> test object's bounding box in 3d */
-
- CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, ((PROJECT_TREE_LEAF *)Tree)->Object,
- &((PROJECT_TREE_LEAF *)Tree)->Object->Bounds, &rayinfo);
-
- break;
-
- /* default:
-
- The node/leaf is pruned and needn't be checked */
-
- }
- }
-
- /* Now test the candidates in the priority queue */
-
- while (Qsize > 0)
- {
- PriorityQueueDelete(Tree_Leaf_Queue, &Qsize, &key, &Object);
-
- if (key > Best_Intersection->Depth)
- break;
-
- if (Intersection(&New_Intersection, Object, Ray))
- {
- if (New_Intersection.Depth < Best_Intersection->Depth)
- {
- *Best_Intersection = New_Intersection;
- Found = TRUE;
- }
- }
- }
-
- break;
-
-
-
- /************************************************************************
- * Use bounding slab tests for all nodes that pass the projection test.
- *************************************************************************/
-
- case PROJECTIONS_WITH_NODE_SLABS :
-
- /* Create the direction vectors for this ray */
-
- Create_Rayinfo(Ray, &rayinfo);
-
- /* Check root */
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, (OBJECT *)Tree,
- &Tree->Object->Bounds, &rayinfo);
- }
-
- while (Qsize > 0)
- {
- PriorityQueueDelete(Tree_Leaf_Queue, &Qsize, &key, &Object);
-
- if (key > Best_Intersection->Depth)
- break;
-
- Tree = (PROJECT_TREE_NODE *)Object;
-
- switch (Tree->is_leaf)
- {
- case FALSE:
-
- /* Check siblings of the unpruned node in 2d */
-
- for (i = 0; i < Tree->Entries; i++)
- {
- Node = Tree->Entry[i];
-
- /* Check unpruned siblings only */
-
- if (Node->is_leaf < PRUNE_CHECK)
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Node->Project.x1) && (x <= Node->Project.x2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, (OBJECT *)Node,
- &Node->Object->Bounds, &rayinfo);
- }
- }
- }
-
- break;
-
- case TRUE:
-
- /* Unpruned leaf --> test object */
-
- if (Intersection(&New_Intersection, ((PROJECT_TREE_LEAF *)Tree)->Object, Ray))
- {
- if (New_Intersection.Depth < Best_Intersection->Depth)
- {
- *Best_Intersection = New_Intersection;
- Found = TRUE;
- }
- }
-
- break;
-
- /* default:
-
- The node/leaf is pruned and needn't be checked */
-
- }
- }
-
- break;
-
-
-
- default :
- Fatal_Error("Unkown algorithm.\n");
- }
-
- return(Found);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Intersect_Light_Tree
- *
- * ARGUMENTS : Ray - Shadow ray
- * Tree - Light tree's top-node
- * x - X-coordinate of the shadow ray
- * y - Y-coordinate of the shadow ray
- * Best_Intersection - Intersection found
- * Best_Object - Object found
- *
- * MODIFIED ARGS : Best_Intersection, Best_Object
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Intersect a shadow ray with the light tree
- * (same as for the vista tree but without pruning).
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- int Intersect_Light_Tree(Ray, Tree, x, y, Best_Intersection, Best_Object)
- RAY *Ray;
- PROJECT_TREE_NODE *Tree;
- int x, y;
- INTERSECTION *Best_Intersection;
- OBJECT **Best_Object;
- {
- INTERSECTION New_Intersection;
- unsigned short i;
- unsigned Qsize, size;
- int Found;
- RAYINFO rayinfo;
- DBL key;
- OBJECT *Object;
- PROJECT_TREE_NODE *Node;
-
- /* Start with an empty priority queue */
-
- Qsize = 0;
-
- Found = FALSE;
-
- totalQueueResets++;
-
- /* which algorithm to use? */
-
- switch (Project_Algorithm)
- {
- /************************************************************************
- * Do not use any bounding slab tests. just use their projections.
- *************************************************************************/
-
- case PROJECTIONS_WITHOUT_SLABS :
-
- /* Check root */
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2) &&
- (y >= Tree->Project.y1) && (y <= Tree->Project.y2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- Tree_Node_Queue[Qsize++] = Tree;
- }
-
- while (Qsize > 0)
- {
- Tree = Tree_Node_Queue[--Qsize];
-
- if (Tree->is_leaf)
- {
- /* Leaf --> test object */
-
- if (Intersection(&New_Intersection, ((PROJECT_TREE_LEAF *)Tree)->Object, Ray))
- {
- if (New_Intersection.Depth < Best_Intersection->Depth)
- {
- *Best_Intersection = New_Intersection;
- *Best_Object = ((PROJECT_TREE_LEAF *)Tree)->Object;
- Found = TRUE;
- }
- }
- }
- else
- {
- /* Check siblings of the node in 2d */
-
- for (i = 0; i < Tree->Entries; i++)
- {
- Node = Tree->Entry[i];
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Node->Project.x1) && (x <= Node->Project.x2) &&
- (y >= Node->Project.y1) && (y <= Node->Project.y2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- /* Add node to node queue */
-
- if (Qsize >= MAXQUEUE)
- Fatal_Error("Node queue overflow.\n");
-
- Tree_Node_Queue[Qsize++] = Node;
- }
- }
- }
- }
-
- break;
-
-
-
- /************************************************************************
- * Use bounding slab tests for leaves (i.e. objects) in the tree.
- *************************************************************************/
-
- case PROJECTIONS_WITH_LEAF_SLABS :
-
- /* Create the direction vectors for this ray */
-
- Create_Rayinfo(Ray, &rayinfo);
-
- /* Fill the priority queue with all possible candidates */
-
- size = 0;
-
- /* Check root */
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2) &&
- (y >= Tree->Project.y1) && (y <= Tree->Project.y2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- Tree_Node_Queue[size++] = Tree;
- }
-
- while (size > 0)
- {
- Tree = Tree_Node_Queue[--size];
-
- if (Tree->is_leaf)
- {
- /* Leaf --> test object's bounding box in 3d */
-
- CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, ((PROJECT_TREE_LEAF *)Tree)->Object,
- &((PROJECT_TREE_LEAF *)Tree)->Object->Bounds, &rayinfo);
- }
- else
- {
- /* Check siblings of the node in 2d */
-
- for (i = 0; i < Tree->Entries; i++)
- {
- Node = Tree->Entry[i];
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Node->Project.x1) && (x <= Node->Project.x2) &&
- (y >= Node->Project.y1) && (y <= Node->Project.y2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- /* Add node to node queue */
-
- if (size >= MAXQUEUE)
- Fatal_Error("Node queue overflow.\n");
-
- Tree_Node_Queue[size++] = Node;
- }
- }
- }
- }
-
- /* Now test the candidates in the priority queue */
-
- while (Qsize > 0)
- {
- PriorityQueueDelete(Tree_Leaf_Queue, &Qsize, &key, &Object);
-
- if (key > Best_Intersection->Depth)
- break;
-
- if (Intersection(&New_Intersection, Object, Ray))
- {
- if (New_Intersection.Depth < Best_Intersection->Depth)
- {
- *Best_Intersection = New_Intersection;
- *Best_Object = Object;
- Found = TRUE;
- }
- }
- }
-
- break;
-
-
-
- /************************************************************************
- * Use bounding slab tests for all nodes that pass the projection test.
- *************************************************************************/
-
- case PROJECTIONS_WITH_NODE_SLABS :
-
- /* Create the direction vectors for this ray */
-
- Create_Rayinfo(Ray, &rayinfo);
-
- /* Check root */
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2) &&
- (y >= Tree->Project.y1) && (y <= Tree->Project.y2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, (OBJECT *)Tree,
- &Tree->Object->Bounds, &rayinfo);
- }
-
- while (Qsize > 0)
- {
- PriorityQueueDelete(Tree_Leaf_Queue, &Qsize, &key, &Object);
-
- if (key > Best_Intersection->Depth)
- break;
-
- Tree = (PROJECT_TREE_NODE *)Object;
-
- if (Tree->is_leaf)
- {
- /* Leaf --> test object */
-
- if (Intersection(&New_Intersection, ((PROJECT_TREE_LEAF *)Tree)->Object, Ray))
- {
- if (New_Intersection.Depth < Best_Intersection->Depth)
- {
- *Best_Intersection = New_Intersection;
- *Best_Object = ((PROJECT_TREE_LEAF *)Tree)->Object;
- Found = TRUE;
- }
- }
- }
- else
- {
- /* Check siblings of the unpruned node in 2d */
-
- for (i = 0; i < Tree->Entries; i++)
- {
- Node = Tree->Entry[i];
-
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests++;
- #endif
-
- if ((x >= Node->Project.x1) && (x <= Node->Project.x2) &&
- (y >= Node->Project.y1) && (y <= Node->Project.y2))
- {
- #ifdef COUNT_PROJECT_TESTS
- Project_Tests_Succeeded++;
- #endif
-
- CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, (OBJECT *)Node,
- &Node->Object->Bounds, &rayinfo);
- }
- }
- }
- }
-
- break;
-
-
-
- default :
- Fatal_Error("Unkown algorithm.\n");
- }
-
- return(Found);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_triangle
- *
- * ARGUMENTS : Project - Triangle's projection
- * P1, P2, P3 - Triangle's edges
- * visible - Flag if triangle is visible
- *
- * MODIFIED ARGS : Project, visible
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project a triangle onto the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_triangle (Project, P1, P2, P3, visible)
- PROJECT *Project;
- VECTOR P1, P2, P3;
- int *visible;
- {
- VECTOR Points[MAX_CLIP_POINTS];
- int i, number;
- int x, y;
-
- Points[0] = P1;
- Points[1] = P2;
- Points[2] = P3;
-
- number = 3;
-
- /* Clip triangle only if some quick tests say it's necessary.
- Assuming that only a few triangles need clipping this saves some time.
- (I don't need to write fabs(1+P?.z) since the tests succeed anyway if
- P?.z < -1. Hope the compiler doesn't change the tests' order!) */
-
- if ((P1.z < -1.0) || (P2.z < -1.0) || (P3.z < -1.0) ||
- (fabs(P1.x) > 0.5*(1.0+P1.z)) || (fabs(P1.y) > 0.5*(1.0+P1.z)) ||
- (fabs(P2.x) > 0.5*(1.0+P2.z)) || (fabs(P2.y) > 0.5*(1.0+P2.z)) ||
- (fabs(P3.x) > 0.5*(1.0+P3.z)) || (fabs(P3.y) > 0.5*(1.0+P3.z)))
- {
- Clip_Polygon(Points, &number, &VIEW_VX1, &VIEW_VX2, &VIEW_VY1, &VIEW_VY2,
- VIEW_DX1, VIEW_DX2, VIEW_DY1, VIEW_DY2);
- }
-
- if (!number)
- return;
-
- for (i = 0; i < number; i++)
- {
- if (Points[i].z == -1.0)
- {
- Points[i].x = Points[i].y = 0.0;
- }
- else
- {
- Points[i].x = Points[i].x / (1.0 + Points[i].z);
- Points[i].y = Points[i].y / (1.0 + Points[i].z);
- }
-
- x = Frame.Screen_Width/2 + (int)(Frame.Screen_Width * Points[i].x);
- y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * Points[i].y);
-
- if (x < Project->x1) Project->x1 = x;
- if (x > Project->x2) Project->x2 = x;
- if (y < Project->y1) Project->y1 = y;
- if (y > Project->y2) Project->y2 = y;
- }
-
- *visible = TRUE;
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_rectangle
- *
- * ARGUMENTS : Project - Rectangle's projection
- * P1, P2, P3, P4 - Rectangle's edges
- * visible - Flag if rectangle is visible
- *
- * MODIFIED ARGS : Project, visible
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project a rectangle onto the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_rectangle(Project, P1, P2, P3, P4, visible)
- PROJECT *Project;
- VECTOR P1, P2, P3, P4;
- int *visible;
- {
- VECTOR Points[MAX_CLIP_POINTS];
- int i, number;
- int x, y;
-
- Points[0] = P1;
- Points[1] = P2;
- Points[2] = P3;
- Points[3] = P4;
-
- number = 4;
-
- /* Clip square only if some quick tests say it's necessary.
- Assuming that only a few squares need clipping this saves some time.
- (I don't need to write fabs(1+P?.z) since the tests succeed anyway if
- P?.z < -1. Hope the compiler doesn't change the tests' order!) */
-
- if ((P1.z < -1.0) || (P2.z < -1.0) || (P3.z < -1.0) || (P4.z < -1.0) ||
- (fabs(P1.x) > 0.5*(1.0+P1.z)) || (fabs(P1.y) > 0.5*(1.0+P1.z)) ||
- (fabs(P2.x) > 0.5*(1.0+P2.z)) || (fabs(P2.y) > 0.5*(1.0+P2.z)) ||
- (fabs(P3.x) > 0.5*(1.0+P3.z)) || (fabs(P3.y) > 0.5*(1.0+P3.z)) ||
- (fabs(P4.x) > 0.5*(1.0+P4.z)) || (fabs(P4.y) > 0.5*(1.0+P4.z)))
- {
- Clip_Polygon(Points, &number, &VIEW_VX1, &VIEW_VX2, &VIEW_VY1, &VIEW_VY2,
- VIEW_DX1, VIEW_DX2, VIEW_DY1, VIEW_DY2);
- }
-
- if (!number)
- return;
-
- for (i = 0; i < number; i++)
- {
- if (Points[i].z == -1.0)
- {
- Points[i].x = Points[i].y = 0.0;
- }
- else
- {
- Points[i].x = Points[i].x / (1.0 + Points[i].z);
- Points[i].y = Points[i].y / (1.0 + Points[i].z);
- }
-
- x = Frame.Screen_Width/2 + (int)(Frame.Screen_Width * Points[i].x);
- y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * Points[i].y);
-
- if (x < Project->x1) Project->x1 = x;
- if (x > Project->x2) Project->x2 = x;
- if (y < Project->y1) Project->y1 = y;
- if (y > Project->y2) Project->y2 = y;
- }
-
- *visible = TRUE;
- }
-
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_BBox
- *
- * ARGUMENTS : Project - Box's projection
- * Points - Box's edges
- * visible - Flag if box is visible
- *
- * MODIFIED ARGS : Project, visible
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project a box onto the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_Bbox(Project, Points, visible)
- PROJECT *Project;
- VECTOR *Points;
- int *visible;
- {
- int vis;
- PROJECT New;
-
- New.x1 = MAX_VB_ENTRY;
- New.x2 = MIN_VB_ENTRY;
- New.y1 = MAX_VB_ENTRY;
- New.y2 = MIN_VB_ENTRY;
-
- vis = FALSE;
-
- Project_rectangle(&New, Points[0], Points[1], Points[3], Points[2], &vis);
- Project_rectangle(&New, Points[4], Points[5], Points[7], Points[6], &vis);
- Project_rectangle(&New, Points[0], Points[1], Points[5], Points[4], &vis);
- Project_rectangle(&New, Points[2], Points[3], Points[7], Points[6], &vis);
- Project_rectangle(&New, Points[1], Points[3], Points[7], Points[5], &vis);
- Project_rectangle(&New, Points[0], Points[2], Points[6], Points[4], &vis);
-
- if (vis)
- {
- if (New.x1 > Project->x1) Project->x1 = New.x1;
- if (New.x2 < Project->x2) Project->x2 = New.x2;
- if (New.y1 > Project->y1) Project->y1 = New.y1;
- if (New.y2 < Project->y2) Project->y2 = New.y2;
- *visible = TRUE;
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_Bounds
- *
- * ARGUMENTS : Project - Bounding box's projection
- * Bounds - Bounding box
- * visible - Flag if bounding box is visible
- *
- * MODIFIED ARGS : Project, visible
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project a bounding box onto the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_Bounds(Project, Bounds, visible)
- PROJECT *Project;
- BBOX *Bounds;
- int *visible;
- {
- int i;
- VECTOR P[8];
-
- for (i = 0; i<8; i++)
- {
- P[i] = Bounds->Lower_Left;
-
- P[i].x += ((i & 1) ? Bounds->Lengths.x : 0.0);
- P[i].y += ((i & 2) ? Bounds->Lengths.y : 0.0);
- P[i].z += ((i & 4) ? Bounds->Lengths.z : 0.0);
-
- Transform_Point (&P[i]);
- }
-
- Project_Bbox(Project, &P[0], visible);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_Bicubic_Patch
- *
- * ARGUMENTS : Project - Projection
- * Object - Object
- *
- * MODIFIED ARGS : Project
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project the bounding sphere of a bicubic patch onto the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_Bicubic_Patch(Project, Object)
- PROJECT *Project;
- OBJECT *Object;
- {
- BICUBIC_PATCH *patch;
- DBL x, y, z, r, a20, a02, a11, a10, a01, a00;
- MATRIX A;
-
- patch = (BICUBIC_PATCH *)Object;
-
- /* Set up 4x4 quadric matrix A */
-
- x = patch->Bounding_Sphere_Center.x;
- y = patch->Bounding_Sphere_Center.y;
- z = patch->Bounding_Sphere_Center.z;
-
- r = 1.0 / (patch->Bounding_Sphere_Radius * patch->Bounding_Sphere_Radius);
-
- A[0][0] = r; A[0][1] = 0.0; A[0][2] = 0.0; A[0][3] = -x*r;
- A[1][0] = 0.0; A[1][1] = r; A[1][2] = 0.0; A[1][3] = -y*r;
- A[2][0] = 0.0; A[2][1] = 0.0; A[2][2] = r; A[2][3] = -z*r;
- A[3][0] = -x*r; A[3][1] = -y*r; A[3][2] = -z*r; A[3][3] = r*(x*x+y*y+z*z) - 1.0;
-
- Project_Vista(&A, NULL, &a20, &a02, &a11, &a10, &a01, &a00);
-
- /* Get vista's bounding rectangle */
-
- Get_Ellipse_Projection(Project, a20, a02, a11, a10, a01, a00);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_Box
- *
- * ARGUMENTS : Project - Projection
- * Object - Object
- * visible - Flag if object is visible
- *
- * MODIFIED ARGS : Project, visible
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project a box onto the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_Box(Project, Object, visible)
- PROJECT *Project;
- OBJECT *Object;
- int *visible;
- {
- int i;
- VECTOR P[8];
- BOX *box;
-
- box = (BOX *)Object;
-
- for (i = 0; i<8; i++)
- {
- P[i] = box->bounds[0];
-
- if (i & 1) P[i].x = box->bounds[1].x;
- if (i & 2) P[i].y = box->bounds[1].y;
- if (i & 4) P[i].z = box->bounds[1].z;
-
- if (box->Trans != NULL)
- MTransPoint(&P[i], &P[i], box->Trans);
-
- Transform_Point (&P[i]);
- }
-
- Project_Bbox(Project, &P[0], visible);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_Height_Field
- *
- * ARGUMENTS : Project - Projection
- * Object - Object
- * visible - Flag if object is visible
- *
- * MODIFIED ARGS : Project, visible
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project the bounding box of a height field onto the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_Height_Field(Project, Object, visible)
- PROJECT *Project;
- OBJECT *Object;
- int *visible;
- {
- int i;
- VECTOR P[8];
- HEIGHT_FIELD *hfield;
-
- hfield = (HEIGHT_FIELD *)Object;
-
- for (i = 0; i<8; i++)
- {
- P[i] = hfield->bounding_box->bounds[0];
-
- if (i & 1) P[i].x = hfield->bounding_box->bounds[1].x;
- if (i & 2) P[i].y = hfield->bounding_box->bounds[1].y;
- if (i & 4) P[i].z = hfield->bounding_box->bounds[1].z;
-
- if (hfield->Trans != NULL)
- MTransPoint(&P[i], &P[i], hfield->Trans);
-
- Transform_Point (&P[i]);
- }
-
- Project_Bbox(Project, &P[0], visible);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_Triangle
- *
- * ARGUMENTS : Project - Projection
- * Object - Object
- * visible - Flag if object is visible
- *
- * MODIFIED ARGS : Project, visible
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project a triangle onto the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_Triangle(Project, Object, visible)
- PROJECT *Project;
- OBJECT *Object;
- int *visible;
- {
- int i, vis;
- VECTOR P[3];
- PROJECT New;
-
- New.x1 = MAX_VB_ENTRY;
- New.x2 = MIN_VB_ENTRY;
- New.y1 = MAX_VB_ENTRY;
- New.y2 = MIN_VB_ENTRY;
-
- P[0] = ((TRIANGLE *)Object)->P1;
- P[1] = ((TRIANGLE *)Object)->P2;
- P[2] = ((TRIANGLE *)Object)->P3;
-
- for (i = 0; i < 3; i++)
- {
- Transform_Point(&P[i]);
- }
-
- vis = FALSE;
-
- Project_triangle(&New, P[0], P[1], P[2], &vis);
-
- if (vis)
- {
- if (New.x1 > Project->x1) Project->x1 = New.x1;
- if (New.x2 < Project->x2) Project->x2 = New.x2;
- if (New.y1 > Project->y1) Project->y1 = New.y1;
- if (New.y2 < Project->y2) Project->y2 = New.y2;
- *visible = TRUE;
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_Smooth_Triangle
- *
- * ARGUMENTS : Project - Projection
- * Object - Object
- * visible - Flag if object is visible
- *
- * MODIFIED ARGS : Project, visible
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project a smooth triangle onto the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_Smooth_Triangle(Project, Object, visible)
- PROJECT *Project;
- OBJECT *Object;
- int *visible;
- {
- int i, vis;
- VECTOR P[3];
- PROJECT New;
-
- New.x1 = MAX_VB_ENTRY;
- New.x2 = MIN_VB_ENTRY;
- New.y1 = MAX_VB_ENTRY;
- New.y2 = MIN_VB_ENTRY;
-
- P[0] = ((SMOOTH_TRIANGLE *)Object)->P1;
- P[1] = ((SMOOTH_TRIANGLE *)Object)->P2;
- P[2] = ((SMOOTH_TRIANGLE *)Object)->P3;
-
- for (i = 0; i < 3; i++)
- {
- Transform_Point(&P[i]);
- }
-
- vis = FALSE;
-
- Project_triangle(&New, P[0], P[1], P[2], &vis);
-
- if (vis)
- {
- if (New.x1 > Project->x1) Project->x1 = New.x1;
- if (New.x2 < Project->x2) Project->x2 = New.x2;
- if (New.y1 > Project->y1) Project->y1 = New.y1;
- if (New.y2 < Project->y2) Project->y2 = New.y2;
- *visible = TRUE;
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_Sphere
- *
- * ARGUMENTS : Project - Projection
- * Object - Oject
- *
- * MODIFIED ARGS : Project
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project a sphere onto the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_Sphere(Project, Object)
- PROJECT *Project;
- OBJECT *Object;
- {
- SPHERE *sphere;
- DBL x, y, z, r, a20, a02, a11, a10, a01, a00;
- MATRIX A;
-
- sphere = (SPHERE *)Object;
-
- /* Set up 4x4 quadric matrix A0 */
-
- x = sphere->Center.x;
- y = sphere->Center.y;
- z = sphere->Center.z;
-
- r = 1.0/sphere->Radius_Squared;
-
- A[0][0] = r; A[0][1] = 0.0; A[0][2] = 0.0; A[0][3] = -x*r;
- A[1][0] = 0.0; A[1][1] = r; A[1][2] = 0.0; A[1][3] = -y*r;
- A[2][0] = 0.0; A[2][1] = 0.0; A[2][2] = r; A[2][3] = -z*r;
- A[3][0] = -x*r; A[3][1] = -y*r; A[3][2] = -z*r; A[3][3] = r*(x*x+y*y+z*z) - 1.0;
-
- Project_Vista(&A, sphere->Trans, &a20, &a02, &a11, &a10, &a01, &a00);
-
- /* get vista's bounding rectangle */
-
- Get_Ellipse_Projection(Project, a20, a02, a11, a10, a01, a00);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Get_Ellipse_Projection
- *
- * ARGUMENTS : Project - Projection
- * a20, a02, a11,
- * a10, a01, a00 - Parameters of the quadratic curve
- *
- * MODIFIED ARGS : Project
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Get the bounding rectangle around an ellipse, i.e. the
- * quadratic curve: a20*x*x + a02*y*y + a11*x*y + a10*x + a01*y + a00 = 0
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Get_Ellipse_Projection(Project, a20, a02, a11, a10, a01, a00)
- PROJECT *Project;
- DBL a20, a02, a11, a10, a01, a00;
- {
- int x1i, x2i, y1i, y2i;
- DBL x1, y1, x2, y2;
- DBL a, b, c, d, k, k1, k2, k3, k4;
-
- x1 = y1 = -0.5;
- x2 = y2 = +0.5;
-
- k1 = a11/(-2.0*a20);
- k2 = a10/(-2.0*a20);
-
- k3 = a11/(-2.0*a02);
- k4 = a01/(-2.0*a02);
-
- a = a20 + a02*k3*k3 + a11*k3;
-
- b = a10 + 2.0*a02*k3*k4 + a01*k3 + a11*k4;
-
- c = a02*k4*k4 + a01*k4 + a00;
-
- d = b*b - 4.0*a*c;
-
- if (d > 0.0)
- {
- a = 2.0*a;
-
- d = sqrt(d);
-
- x1 = (-b+d)/a;
- x2 = (-b-d)/a;
-
- if (x1>x2)
- {
- k = x1; x1 = x2; x2 = k;
- }
-
- a = a02 + a20*k1*k1 + a11*k1;
-
- b = a01 + 2.0*a20*k1*k2 + a10*k1 + a11*k2;
-
- c = a20*k2*k2 + a10*k2 + a00;
-
- d = b*b - 4.0*a*c;
-
- if (d > 0.0)
- {
- a = 2.0*a;
-
- d = sqrt(d);
-
- y1 = (-b+d)/a;
- y2 = (-b-d)/a;
-
- if (y1>y2)
- {
- k = y1; y1 = y2; y2 = k;
- }
- }
- }
-
- if (x1 < -0.5) x1 = -0.5;
- if (x2 > +0.5) x2 = +0.5;
- if (y1 < -0.5) y1 = -0.5;
- if (y2 > +0.5) y2 = +0.5;
-
- x1i = Frame.Screen_Width/2 + (int)(Frame.Screen_Width * x1) - 1;
- x2i = Frame.Screen_Width/2 + (int)(Frame.Screen_Width * x2) + 1;
-
- y1i = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * y2) - 1;
- y2i = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * y1) + 1;
-
- if (x1i > Project->x1) Project->x1 = x1i;
- if (x2i < Project->x2) Project->x2 = x2i;
-
- if (y1i > Project->y1) Project->y1 = y1i;
- if (y2i < Project->y2) Project->y2 = y2i;
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_Vista
- *
- * ARGUMENTS : A0 - Matrix defining the quadric surface
- * Trans - Transformation matrices
- * a20, a02, a11,
- * a10, a01, a00 - Parameters of the projected quadratic curve
- *
- * MODIFIED ARGS : a20, a02, a11, a10, a01, a00
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project a quadric surface onto the screen (perspective projection)
- * and get the paramters of the resulting quadratic curve.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Project_Vista(A0, Trans, a20, a02, a11, a10, a01, a00)
- MATRIX *A0;
- TRANSFORM *Trans;
- DBL *a20, *a02, *a11, *a10, *a01, *a00;
- {
- int i, j;
- MATRIX Tinv, A1, A2, B, Transposed_Matrix;
- DBL k1, k2, k3;
-
- /* Apply object transformations */
-
- if (Trans == NULL)
- {
- for (i=0;i<4;i++)
- {
- for (j=0;j<4;j++)
- {
- A1[i][j] = (*A0)[i][j];
- }
- }
- }
- else
- {
- MTranspose(&Transposed_Matrix, &Trans->inverse);
- MTimes(&A1, &Trans->inverse, A0);
- MTimes(&A1, &A1, &Transposed_Matrix);
- }
-
- /* Transform into viewing system */
-
- MTranspose(&Transposed_Matrix, &WC2VCinv);
- MTimes(&A2, &Transposed_Matrix, &A1);
- MTimes(&A2, &A2, &WC2VCinv);
-
- /* Calculate quadrics vista */
-
- MIdentity(&Tinv);
-
- Tinv[3][2] = -1.0;
-
- MTranspose(&Transposed_Matrix, &Tinv);
-
- MTimes(&B, &Transposed_Matrix, &A2);
- MTimes(&B, &B, &Tinv);
-
- k1 = (B[0][2]+B[2][0])/(-2.0*B[2][2]);
-
- k2 = (B[1][2]+B[2][1])/(-2.0*B[2][2]);
-
- k3 = (B[2][3]+B[3][2])/(-2.0*B[2][2]);
-
- *a20 = B[0][0] + k1*(B[0][2]+B[2][0]) + k1*k1*B[2][2];
-
- *a02 = B[1][1] + k2*(B[1][2]+B[2][1]) + k2*k2*B[2][2];
-
- *a10 = B[0][3]+B[3][0] + k1*(B[2][3]+B[3][2]) + k3*(B[0][2]+B[2][0]) + 2.0*k1*k3*B[2][2];
-
- *a01 = B[1][3]+B[3][1] + k2*(B[2][3]+B[3][2]) + k3*(B[1][2]+B[2][1]) + 2.0*k2*k3*B[2][2];
-
- *a11 = B[0][1]+B[1][0] + k1*(B[1][2]+B[2][1]) + k2*(B[0][2]+B[2][0]) + 2.0*k1*k2*B[2][2];
-
- *a00 = B[3][3] + k3*(B[2][3]+B[3][2]) + k3*k3*B[2][2];
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Transform_Point
- *
- * ARGUMENTS : P - Point to transform
- *
- * MODIFIED ARGS : P
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Transform a point from the world coordinate system to the viewer's
- * coordinate system.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Transform_Point(P)
- VECTOR *P;
- {
- DBL x,y,z;
-
- x = P->x - O.x;
- y = P->y - O.y;
- z = P->z - O.z;
-
- P->x = U.x * x + U.y * y + U.z * z;
- P->y = V.x * x + V.y * y + V.z * z;
- P->z = W.x * x + W.y * y + W.z * z;
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Init_View_Coordinates
- *
- * ARGUMENTS : none
- *
- * MODIFIED ARGS : none
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Init the matrices and vectors used to transform a point from
- * the world coordinate system to the viewer's coordinate system.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Init_View_Coordinates()
- {
- DBL k, up_length, right_length;
- MATRIX A, B;
-
- U = Frame.Camera->Right;
- V = Frame.Camera->Up;
- W = Frame.Camera->Direction;
-
- VAdd (O, Frame.Camera->Location, Frame.Camera->Direction);
-
- VNormalize(U,U);
- VNormalize(V,V);
- VNormalize(W,W);
-
- VDot(k, U,V);
- if (fabs(k) > EPSILON)
- Fatal_Error("Camera: Right-vector not perpendicular to Up-vector.\n");
-
- VDot(k, U,W);
- if (fabs(k) > EPSILON)
- Fatal_Error("Camera: Right-vector not perpendicular to Direction-vector.\n");
-
- VDot(k, V,W);
- if (fabs(k) > EPSILON)
- Fatal_Error("Camera: Up-vector not perpendicular to Direction-vector.\n");
-
- VLength (distance, Frame.Camera->Direction);
-
- VLength (up_length, Frame.Camera->Up);
- VLength (right_length, Frame.Camera->Right);
-
- VScaleEq (U, 1.0/right_length);
- VScaleEq (V, 1.0/up_length);
- VScaleEq (W, 1.0/distance);
-
- A[0][0] = U.x; A[0][1] = U.y; A[0][2] = U.z; A[0][3] = 0.0;
- A[1][0] = V.x; A[1][1] = V.y; A[1][2] = V.z; A[1][3] = 0.0;
- A[2][0] = W.x; A[2][1] = W.y; A[2][2] = W.z; A[2][3] = 0.0;
- A[3][0] = 0.0; A[3][1] = 0.0; A[3][2] = 0.0; A[3][3] = 1.0;
-
- B[0][0] = 1.0; B[0][1] = 0.0; B[0][2] = 0.0; B[0][3] = -O.x;
- B[1][0] = 0.0; B[1][1] = 1.0; B[1][2] = 0.0; B[1][3] = -O.y;
- B[2][0] = 0.0; B[2][1] = 0.0; B[2][2] = 1.0; B[2][3] = -O.z;
- B[3][0] = 0.0; B[3][1] = 0.0; B[3][2] = 0.0; B[3][3] = 1.0;
-
- MTimes(&WC2VC, &A, &B);
- MInvers(&WC2VCinv, &WC2VC);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Get_Perspective_Projection
- *
- * ARGUMENTS : Object - Object to project
- * Project - Projection
- * infinite - Flag if object is infinite
- *
- * MODIFIED ARGS : Project
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Get the perspective projection of a single object, i.e.
- * the smallest rectangle enclosing the object's image on the screen.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Get_Perspective_Projection(Object, Project, infinite)
- OBJECT *Object;
- PROJECT *Project;
- int infinite;
- {
- int visible;
- METHODS *Methods;
-
- visible = FALSE;
-
- Methods = Object->Methods;
-
- /* If the object is infinite, there's no sense of projecting */
-
- if (!infinite)
- {
- if ((Methods == &Box_Methods) ||
- (Methods == &Smooth_Triangle_Methods) ||
- (Methods == &Triangle_Methods) ||
- (Methods == &Csg_Height_Field_Methods) ||
- (Methods == &Height_Field_Methods))
- {
- if (Methods == &Box_Methods)
- Project_Box(Project, Object, &visible);
-
- if (Methods == &Csg_Height_Field_Methods)
- Project_Height_Field(Project, Object, &visible);
-
- if (Methods == &Height_Field_Methods)
- Project_Height_Field(Project, Object, &visible);
-
- if (Methods == &Smooth_Triangle_Methods)
- Project_Smooth_Triangle(Project, Object, &visible);
-
- if (Methods == &Triangle_Methods)
- Project_Triangle(Project, Object, &visible);
- }
- else
- {
- Project_Bounds(Project, &Object->Bounds, &visible);
- }
- }
-
- if (visible)
- {
- if (Options & ANTIALIAS)
- {
- /* Increase the rectangle to make sure that nothing will be missed.
- For anti-aliased images increase by a larger amount. */
-
- Project->x1 = max (0, Project->x1 - 2);
- Project->x2 = min (Frame.Screen_Width-1, Project->x2 + 2);
- Project->y1 = max (-1, Project->y1 - 2);
- Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 2);
- }
- else
- {
- /* Increase the rectangle to make sure that nothing will be missed. */
-
- Project->x1 = max (0, Project->x1 - 1);
- Project->x2 = min (Frame.Screen_Width-1, Project->x2 + 1);
- Project->y1 = max (0, Project->y1 - 1);
- Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);
- }
- }
- else
- {
- if (!infinite)
- {
- /* Object is invisible (the camera can't see it) */
-
- Project->x1 = Project->y1 = MAX_VB_ENTRY;
- Project->x2 = Project->y2 = MIN_VB_ENTRY;
- }
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_Object
- *
- * ARGUMENTS : Object - Object to project
- * Project - Projection
- *
- * MODIFIED ARGS : Project
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Get the projection of a single object depending on the camera
- * used (perspective/orthographic).
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_Object(Object, Project)
- OBJECT *Object;
- PROJECT *Project;
- {
- int infinite;
- DBL Volume;
-
- /* Init project fields, assuming the object is visible! */
-
- Project->x1 = Project->y1 = MIN_VB_ENTRY;
- Project->x2 = Project->y2 = MAX_VB_ENTRY;
-
- BOUNDS_VOLUME(Volume, Object->Bounds);
-
- infinite = (Volume > INFINITE_VOLUME);
-
- Get_Perspective_Projection(Object, Project, infinite);
-
- Print_Point(POINT_MOD);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Project_Bounding_Slab
- *
- * ARGUMENTS : Project - Projection
- * Tree - Current node/leaf
- * Object - Node/leaf in bounding slab hierarchy
- *
- * MODIFIED ARGS : Project, Tree
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Project the bounding slab hierarchy onto the screen and thus create
- * the vista buffer hierarchy.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Project_Bounding_Slab(Project, Tree, Object)
- PROJECT *Project;
- PROJECT_TREE_NODE **Tree;
- OBJECT *Object;
- {
- unsigned short int i;
- COMPOSITE *Comp;
- PROJECT Temp;
- PROJECT_TREE_LEAF *Leaf;
- PROJECT_TREE_NODE New;
-
- if (Object->Type & BOUNDING_OBJECT)
- {
- /* Current object is a bounding object, i.e. a node in the slab tree. */
-
- Comp = (COMPOSITE *)Object;
-
- /* First, init new entry. */
-
- New.Entries = 0;
-
- New.Object = Object;
-
- New.Project.x1 = New.Project.y1 = MAX_VB_ENTRY;
- New.Project.x2 = New.Project.y2 = MIN_VB_ENTRY;
-
- /* Allocate temporary memory for node/leaf entries. */
-
- if ((New.Entry = (PROJECT_TREE_NODE **)malloc(Comp->Entries*sizeof(PROJECT_TREE_NODE *))) == NULL)
- {
- Fatal_Error("temporary tree entry");
- }
-
- /* This is no leaf, it's a node. */
-
- New.is_leaf = FALSE;
-
- /* Second, get new entry, i.e. project node's entries. */
-
- for (i = 0; i < Comp->Entries; i++)
- {
- New.Entry[i] = NULL;
-
- Project_Bounding_Slab(&Temp, &New.Entry[New.Entries], Comp->Objects[i]);
-
- /* Use only visible entries */
-
- if (New.Entry[New.Entries] != NULL)
- {
- New.Project.x1 = min(New.Project.x1, Temp.x1);
- New.Project.x2 = max(New.Project.x2, Temp.x2);
- New.Project.y1 = min(New.Project.y1, Temp.y1);
- New.Project.y2 = max(New.Project.y2, Temp.y2);
-
- New.Entries++;
- }
- }
-
- /* If there are any visible entires, we'll use them. */
-
- if (New.Entries > 0)
- {
- /* If there's only one entry, we won't need a new node. */
-
- if (New.Entries == 1)
- {
- *Tree = New.Entry[0];
- *Project = New.Project;
- }
- else
- {
- /* Allocate memory for new node in the vista tree (never freed!) */
-
- *Tree = (PROJECT_TREE_NODE *)VB_malloc(sizeof(PROJECT_TREE_NODE));
-
- if (*Tree == NULL)
- {
- Fatal_MAError("vista tree node");
- }
-
- **Tree = New;
-
- /* Allocate memory for node/leaf entries. */
-
- (*Tree)->Entry = (PROJECT_TREE_NODE **)VB_malloc(New.Entries*sizeof(PROJECT_TREE_NODE *));
-
- if ((*Tree)->Entry == NULL)
- {
- Fatal_MAError("vista tree node");
- }
-
- memcpy((*Tree)->Entry, New.Entry, New.Entries*sizeof(PROJECT_TREE_NODE *));
-
- *Project = New.Project;
- }
- }
-
- /* Get rid of temporary node/leaf entries. */
-
- free(New.Entry);
- }
- else
- {
- /* Current object is a normal object, i.e. a leaf in the slab tree */
-
- /* Get object's projection */
-
- Project_Object(Object, Project);
-
- /* Is the object visible? */
-
- if ((Project->x1 <= Project->x2) && (Project->y1 <= Project->y2))
- {
- /* Allocate memory for new leaf in the vista tree (never freed!) */
-
- *Tree = (PROJECT_TREE_NODE *)VB_malloc(sizeof(PROJECT_TREE_LEAF));
-
- if (*Tree == NULL)
- {
- Fatal_MAError("vista tree leaf");
- }
-
- /* Init new leaf */
-
- Leaf = (PROJECT_TREE_LEAF *)(*Tree);
-
- Leaf->Object = Object;
-
- Leaf->Project = *Project;
-
- /* Yes, this is a leaf */
-
- Leaf->is_leaf = TRUE;
- }
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION : Build_Vista_Tree
- *
- * ARGUMENTS : none
- *
- * MODIFIED ARGS : none
- *
- * RETURN VALUE : none
- *
- * AUTHOR : Dieter Bayer, May 1994
- *
- * DESCRIPTION
- *
- * Build the vista tree, i.e. the 2d representation of the bounding slab
- * hierarchy in image space.
- *
- * This only works for perspective and orthographic cameras.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Build_Vista_Tree()
- {
- PROJECT Project;
-
- Root_Vista = NULL;
-
- if (Use_Slabs)
- {
- fprintf(stderr, "Building vista buffer");
-
- Begin_Point();
-
- Project_Bounding_Slab(&Project, &Root_Vista, Root_Object);
-
- End_Point();
- }
- }
-
-
-
- #endif
-
-